
#include <stdio.h>
#include <string.h>

/*
 *  0: display测试
 *  1: 透视投影测试
 *  2: 三角形遍历测试
 *  3: 按键/触屏输入测试
 *  4: input设备测试
 *  5: 3d模型、相机、输入、显示联调
 *  6: 文件读写测试
 *  7: 多线程时间同步测试
 *  8: sys_heart测试
 *  9: 十字链表测试
 *  10: 流程测试
 *  11: 数据类型测试
 */
#define TEST 5

#if (TEST == 11)

#include <unistd.h>
#include "value_format.h"

int test(void)
{
    //数据初始化,分隔符和补零设置
    Value *b = new Value(true); 
    Value *ba = new Value(3, true, false, true);
    Value *c = new Value('R');
    Value *str = new Value((char*)"一三五七九");
    Value *stra = new Value(3, (char*)"1", (char*)"23", (char*)"456"); stra->Sep() = ',';
    Value *i = new Value(10086); i->Sep() = '%';
    Value *ia = new Value(3, 12, 34, 56); ia->Zero() = 8; ia->Sep() = '-';
    Value *d = new Value(123.123456789); d->Zero() = 10;
    Value *da = new Value(3, 12.34, 5.678, 9.0123); da->Sep() = '@';
    Value *p = new Value(d);
    Value *pa = new Value(3, d, da, i); pa->Sep() = '_';
    Value *va = new Value(4, VT_BOOL, VT_STRING, VT_DOUBLE_ARRAY, VT_INT); va->Sep() = '+';

    //value数组进一步初始化
    va->GetValueArray()[1].Reset((char*)"abcd");
    va->GetValueArray()[2].Reset(3, 1.23, 4.56, 7.89);
    va->GetValueArray()[2].Sep() = '_';
    va->GetValueArray()[3].GetInt() = 10086;

    //拷贝构造
    Value *dac = new Value(*da); dac->Sep() = '\t';
    Value *strac = new Value(*stra); strac->Sep() = '\n';
    Value *vac = new Value(*va); vac->Sep() = '=';

    printf("\r\n>>> Base test\r\n");

    b->Print();
    ba->Print();
    c->Print();
    str->Print();
    stra->Print();
    i->Print();
    ia->Print();
    d->Print();
    da->Print();
    p->Print();
    pa->Print();
    va->Print();

    dac->Print();
    strac->Print();
    vac->Print();

    b->PrintJson();
    ba->PrintJson();
    c->PrintJson();
    str->PrintJson();
    stra->PrintJson();
    i->PrintJson();
    ia->PrintJson();
    d->PrintJson();
    da->PrintJson();
    p->PrintJson();
    pa->PrintJson();
    va->PrintJson();

    dac->PrintJson();
    strac->PrintJson();
    vac->PrintJson();

    printf("\r\n>>> ArrayAdd test\r\n");

    ba->ArrayAdd(true);
    stra->ArrayAdd((char*)"addstr");
    da->ArrayAdd(98.7654321);
    pa->ArrayAdd((void*)&ba);
    va->ArrayAdd(&va->GetValueArray()[2]);

    ba->Print();
    stra->Print();
    da->Print();
    pa->Print();
    va->Print();

    ba->PrintJson();
    stra->PrintJson();
    da->PrintJson();
    pa->PrintJson();
    va->PrintJson();

    printf("\r\n>>> ToValueArray test\r\n");

    b->ArrayAdd(123);
    ba->ArrayAdd(123);
    c->ArrayAdd(123);
    str->ArrayAdd(123);
    stra->ArrayAdd(123);
    i->ArrayAdd("123");

    // b->ToValueArray();
    // ba->ToValueArray();
    // c->ToValueArray();
    // str->ToValueArray();
    // stra->ToValueArray();
    // i->ToValueArray();
    ia->ToValueArray();
    d->ToValueArray();
    da->ToValueArray();
    p->ToValueArray();
    pa->ToValueArray();
    va->ToValueArray();

    dac->ToValueArray();
    strac->ToValueArray();
    vac->ToValueArray();

    b->PrintJson();
    ba->PrintJson();
    c->PrintJson();
    str->PrintJson();
    stra->PrintJson();
    i->PrintJson();
    ia->PrintJson();
    d->PrintJson();
    da->PrintJson();
    p->PrintJson();
    pa->PrintJson();
    va->PrintJson();

    dac->PrintJson();
    strac->PrintJson();
    vac->PrintJson();

    //内存回收
    delete b;
    delete ba;
    delete c;
    delete str;
    delete stra;
    delete i;
    delete ia;
    delete d;
    delete da;
    delete p;
    delete pa;
    delete va;

    delete dac;
    delete strac;
    delete vac;

    printf(" ----- test end ----- \r\n");
    return 0;
}

int main()
{
    // test();
    
    //检查内存增长
    while(1)
    {
        test();
        sleep(1);
    }

    return 0;
}

#elif (TEST == 10)

#include <stdio.h>
#include "sys_global.h"
#include "scene_global.h"
#include "util_delay.h"

int main(void)
{
    SysInit();
    printf(" ----- step 1 ----- \r\n");

    SysFlowNext(new SceneOpening());
    printf(" ----- step 2 ----- \r\n");

    UtilDelayMs(3000);
    printf(" ----- step 3 ----- \r\n");

    SysDeInit();
    printf(" ----- test end ----- \r\n");
    return 0;
}

#elif (TEST == 9)

#include <stdio.h>
#include "crosslist_base.h"

int main(void)
{
    CrossList *tempNode;
    CrossList *root = new CrossList();

    printf(" ----- step 1 ----- \r\n");

    for (int i = 1; i < 10; i++)
    {
        if (i % 2)
            root->PushFront(new CrossList());
        else
            root->PushBack(new CrossList());
    }

    printf(" ----- step 2 ----- \r\n");

    for (int i = 0; i < 10; i++)
    {
        if (i % 2)
            root->PushFrontChild(new CrossList());
        else
            root->PushBackChild(new CrossList());
    }

    printf(" ----- step 3 ----- \r\n");

    tempNode = root->At(0);
    while (tempNode)
    {
        printf("index: %d, parent: %p, prev: %p, next: %p, child: %d, fc: %p, lc: %p \r\n",
            tempNode->Index(),
            tempNode->Parent(),
            tempNode->Prev(),
            tempNode->Next(),
            tempNode->Child(),
            tempNode->FirstChild(),
            tempNode->LastChild());
        tempNode = tempNode->Next();
    }

    printf(" ----- step 4 ----- \r\n");

    tempNode = root->ChildAt(0);
    while (tempNode)
    {
        printf("index: %d, parent: %p, prev: %p, next: %p, child: %d, fc: %p, lc: %p \r\n",
            tempNode->Index(),
            tempNode->Parent(),
            tempNode->Prev(),
            tempNode->Next(),
            tempNode->Child(),
            tempNode->FirstChild(),
            tempNode->LastChild());
        tempNode = tempNode->Next();
    }

    printf(" ----- step 5 ----- \r\n");

    tempNode = root->At(0);
    while (tempNode->Next())
    {
        tempNode = tempNode->Next();
        delete tempNode->Prev();
    }
    delete tempNode;

    printf(" ----- test end ----- \r\n");
    return 0;
}

#elif (TEST == 8)

#include <stdio.h>
#include "util_delay.h"
#include "sys_global.h"

int32_t heartCallback(void* priv, SysHeartType type, int32_t index)
{
    printf("heart: type %d, index %d \r\n", type, index);
    return 0;
}

int32_t main(void)
{
    SysInit();
    printf(" ----- step 1 ----- \r\n");

    SysHeartUser *usr1 = SysHeartRegister(NULL, &heartCallback, SYS_HERAT_TYPE_MAP_ANIM);
    SysHeartUser *usr2 = SysHeartRegister(NULL, &heartCallback, SYS_HERAT_TYPE_UNIT_STANDBY);
    SysHeartUser *usr3 = SysHeartRegister(NULL, &heartCallback, SYS_HERAT_TYPE_UNIT_SELECT);
    // SysHeartUser *usr4 = SysHeartRegister(NULL, &heartCallback, SYS_HERAT_TYPE_UNIT_RUNNING);

    printf(" ----- step 2 ----- \r\n");
    for (int i = 0; i < 5; i++)
    {
        UtilDelayUs(1000000);
        if (i == 1)
            SysHeartUnRegister(usr1);
        else if (i == 2)
        {
            SysHeartUnRegister(usr2);
            SysHeartSwitch(usr3, SYS_HERAT_TYPE_UNIT_STANDBY);
        }
    }

    printf(" ----- step 3 ----- \r\n");
    SysDeInit();

    printf(" ----- test end ----- \r\n");
    return 0;
}

#elif (TEST == 7)

#include <stdio.h>
#include <stdlib.h>
#include "util_delay.h"
#include "util_thread.h"
#include "util_rand.h"

typedef struct {
    int32_t index;
    uint32_t intervalUs;
} ThreadStruct;

void* fun(void *argv)
{
    ThreadStruct* ts = (ThreadStruct*)argv;
    while(1)
    {
        UTIL_DELAY_NEXT_US(ts->intervalUs);
        // UTIL_DELAY_US(ts->intervalUs);

        printf("%dth - %s\r\n", ts->index, UtilGetTimeStampSSMMMUUU());

        //随机耗时
        UtilDelayUs(UtilRand() % (ts->intervalUs * 3 / 4));
    }
    return NULL;
}

int32_t main(int32_t argc, char **argv)
{
    ThreadStruct ts[] = {
        {1, 500000},
        {2, 500000},
        {3, 500000},
    };

    for (int32_t i = 0; i < sizeof(ts) / sizeof(ts[0]); i++)
        UtilThreadNew(&ts[i], fun);

    while (1)
        UtilDelayUs(1000000);

    return 0;
}

#elif (TEST == 6)

#include <stdio.h>
#include "sys_global.h"

int32_t main(int32_t argc, char **argv)
{
    char buff[128] = {0};
    int32_t ret;

    SysInit();

    ret = SysFileCreate("test1/file/");
    printf("SysFileCreate(%d): \r\n", ret);

    ret = SysFileWriteAll("test1/file/f1.txt", (char*)"01234\n56789\nabcde\n", 18);
    printf("SysFileWriteAll(%d): \r\n", ret);

    ret = SysFileAppend("test1/file/f1.txt", "fghij = %d\n", 10086);
    printf("SysFileAppend(%d): \r\n", ret);

    ret = SysFileSizeOf("test1/file/f1.txt");
    printf("SysFileSizeOf(%d): \r\n", ret);

    ret = SysFileReadLine("test1/file/f1.txt", buff, sizeof(buff), 2);
    printf("SysFileReadLine(%d): %s\r\n", ret, buff);

    ret = SysFileReadAll("test1/file/f1.txt", buff, sizeof(buff));
    printf("SysFileReadAll(%d): %s\r\n", ret, buff);

    ret = SysFileCopy("test2", "test1");
    printf("SysFileCopy(%d): \r\n", ret);

    ret = SysFileMove("test3", "test1");
    printf("SysFileMove(%d): \r\n", ret);

    ret = SysFileDelete("test1");
    printf("SysFileDelete(%d): \r\n", ret);

    ret = SysFileDelete("test2");
    printf("SysFileDelete(%d): \r\n", ret);

    ret = SysFileDelete("test3");
    printf("SysFileDelete(%d): \r\n", ret);

    SysDeInit();

    printf(" ----- test end ----- \r\n");
    return 0;
}

#elif (TEST == 5)

#include "3d_camera.h"
#include "3d_canva.h"
#include "3d_model.h"
#include "plat_input.h"
#include "plat_display.h"
#include "util_delay.h"
#include "util_picture.h"

#define LINE_LENGTH 120
#define TRIANGLE_LENGTH 100
#define RECT_WIDTH 100
#define RECT_HEIGHT 60

static void KeyCallback(void *priv, PlatInputKey key, PlatInputState state)
{
    D3Camera *camera = (D3Camera*)priv;
    // printf("key: %d  state: %d\r\n", key, state);

    const float divRoll = 2;
    const float divMove = 2;

    float frontBack = 0, leftRight = 0, upDown = 0;
    float turnUpDown = 0, turnLeftRight = 0, rollLeftRight = 0;

    if (state <= PIS_UP)
        return;

    switch(key)
    {
    case PIK_UP: frontBack = divMove; break;
    case PIK_DOWN: frontBack = -divMove; break;
    case PIK_LEFT: leftRight = divMove; break;
    case PIK_RIGHT: leftRight = -divMove; break;

    case PIK_UP_LEFT: upDown = divMove; break;
    case PIK_UP_RIGHT: upDown = -divMove; break;
    case PIK_DOWN_LEFT: frontBack = divMove; break;
    case PIK_DOWN_RIGHT: frontBack = divMove; break;

    case PIK_BACK: camera->Reset(); return;
    case PIK_HOME: break;

    case PIK_ARROW_UP: turnUpDown = -divRoll; break;
    case PIK_ARROW_DOWN: turnUpDown = divRoll; break;
    case PIK_ARROW_LEFT: turnLeftRight = divRoll; break;
    case PIK_ARROW_RIGHT: turnLeftRight = -divRoll; break;

    default: return;
    }

    camera->MoveSelf(frontBack, leftRight, upDown);
    camera->RollSelf(turnUpDown, 0, rollLeftRight);
    camera->Roll(0, 0, turnLeftRight);
}

int32_t main(void)
{
    D3Camera camera(480, 320); //300x300相机屏幕
    D3Canva canva(&camera); //画布
    D3Model model;
    Image imageSig, imageMap, imageAnim;
    Film filmSig, filmMap, filmAnim;
    PlatInput input;
    PlatDisplay display;

    imageSig = UtilPicGet("./res/signal.png");
    filmSig.Init(&imageSig);
    imageMap = UtilPicGet("./res/map.jpg");
    filmMap.Init(&imageMap);
    imageAnim = UtilPicGet("./res/000.png");
    filmAnim.Init(&imageAnim, 18);

    //xyz坐标轴 - 连线
    model.AddLine(LINE_LENGTH, 0, 0, -LINE_LENGTH, 0, 0, 0xFF0000);
    model.AddLine(0, LINE_LENGTH, 0, 0, -LINE_LENGTH, 0, 0x00FF00);
    model.AddLine(0, 0, LINE_LENGTH, 0, 0, -LINE_LENGTH, 0x0000FF);

    //map - 跨-x-y平面
    model.AddRect(
        120, 200, -30,
        120, -200, -30,
        -120, -200, -30,
        -120, 200, -30,
        0x80FF0000,
        &filmMap);

    //三角形 - 跨xyz平面
    model.AddTriangle(
        TRIANGLE_LENGTH, 0, 0,
        0, TRIANGLE_LENGTH, 0,
        0, 0, -TRIANGLE_LENGTH,
        0x8000FFFF);

    //动画图片 - 跨+x-y平面
    model.AddRect(
        0, 0, 32-30,
        0, -32, 32-30,
        0, -32, 0-30,
        0, 0, 0-30,
        0x00000000,
        &filmAnim);

    //信号图片 - 跨-x-y平面
    model.AddRect(
        -RECT_WIDTH, 0, RECT_HEIGHT,
        0, 0, RECT_HEIGHT,
        0, 0, 0,
        -RECT_WIDTH, 0, 0,
        0x00000000,
        &filmSig);

    //相机初始位置调整
    camera.SetLocation(-250, -120, 110);
    camera.SetDirection(-20, 20, 0);

    input.SetKeyCallback(&camera, &KeyCallback);
    input.KeyCallbackEnable(true);

    while (1)
    {
        //开画
        canva.Clear();
        canva.Draw(&model);
#if 1
        //输出到图片
        UtilPicCreate("./out.bmp", canva.GetImage());
        UtilDelayUs(500000);
#else
        //输出到fb屏幕
        ImageCover(display.GetMap(), 0, 0, canva.GetWidth(), canva.GetHeight(), canva.GetImage());
        display.Refresh();
        UtilDelayUs(50000);
#endif
        filmAnim.NextIndex();
    }

    return 0;
}

#elif (TEST == 4)

#include "list_input.h"

int32_t main(int32_t argc, char **argv)
{
    ListInputDevice();
    if (argc > 1)
        TestInputDevice(argv[1]);
    return 0;
}

#elif (TEST == 3)

#include "plat_input.h"
#include "util_delay.h"

static void KeyCallback(void *priv, PlatInputKey key, PlatInputState state)
{
    printf("key: %d  state: %d\r\n", key, state);
}
static void TouchCallback(void *priv, int32_t x, int32_t y, PlatInputState state)
{
    printf("touch: %d,%d  state: %d\r\n", x, y, state);
}

int32_t main()
{
    PlatInput input;
    input.SetKeyCallback(NULL, &KeyCallback);
    input.SetTouchCallback(NULL, &TouchCallback);
    input.KeyCallbackEnable(true);
    input.TouchCallbackEnable(true);
    while (1)
        UtilDelayUs(1000000);
    return 0;
}

#elif (TEST == 2)

#include <stdlib.h>
#include "image_format.h"
#include "3d_math.h"
#include "util_bmp.h"
#include "util_delay.h"
#include "util_rand.h"

int32_t main(void)
{
    int32_t ret, i;
    int32_t xy[2 * 3];
    int32_t *retXy;
    uint32_t color = 0;

    //生成300x300图像内存
    Image image = ImageCreate(300, 300, IMAGE_FORMAT_RGB);

    while (1)
    {
        //清空图像
        ImageClear(image, 0);
        
        //随机生成三角形
        for (i = 0; i < 2 * 3; i++)
            xy[i] = UtilRand() % 300;

        //遍历三角形
        ret = triangle_enum(xy, &retXy);

        //随机颜色
        color = UtilRand() % 0xFFFFFF;

        //画三角形
        for (i = 0; i < ret * 2;)
            ImageWrite(image, retXy[i++], retXy[i++], color);
        
        free(retXy);

        //输出到bmp并延时
        UtilBmpCreate("./out.bmp", image.mem.addr, image.info.width, image.info.height, image.info.pb);
        UtilDelayUs(500000);
    }
    return 0;
}

#elif (TEST == 1)

#include "util_print.h"
#include "3d_camera.h"

int32_t main()
{
    D3Camera camera(500, 300); //创建相机: 500x300屏幕
    float xyz[3] = {20, 0, 0}; //空间坐标点初始位置: 距离屏幕60-10=50的位置
    int32_t retXY[2] = {}; //透视投影后返回在屏幕的坐标(左上角0,0)
    float retDepth = 0; //透视投影后返回的深度值0.0~1.0
    int32_t ret = 0; //透视投影后返回的是否入屏

    char in[8] = {0};
    while(1)
    {
        if (scanf("%s", in) > 0)
        {
#if 1
            //空间坐标: 前、后、左、右、上、下移动
            if (in[0] == 'w')
                xyz[0] += 10;
            else if (in[0] == 's')
                xyz[0] -= 10;
            else if (in[0] == 'a')
                xyz[1] += 10;
            else if (in[0] == 'd')
                xyz[1] -= 10;
            else if (in[0] == 'q')
                xyz[2] += 5;
            else if (in[0] == 'e')
                xyz[2] -= 5;
#else
            //相机自身: 前、后、左、右、上、下移动
            if (in[0] == 'w')
                camera.MoveSelf(10, 0, 0);
            else if (in[0] == 's')
                camera.MoveSelf(-10, 0, 0);
            else if (in[0] == 'a')
                camera.MoveSelf(0, 10, 0);
            else if (in[0] == 'd')
                camera.MoveSelf(0, -10, 0);
            else if (in[0] == 'q')
                camera.MoveSelf(0, 0, 10);
            else if (in[0] == 'e')
                camera.MoveSelf(0, 0, -10);
#endif
            //相机自身朝向: 上、下、左、右、逆时针、顺时针旋转
            else if (in[0] == 't')
                camera.RollSelf(-10, 0, 0);
            else if (in[0] == 'g')
                camera.RollSelf(10, 0, 0);
            else if (in[0] == 'f')
                camera.RollSelf(0, 10, 0);
            else if (in[0] == 'h')
                camera.RollSelf(0, -10, 0);
            else if (in[0] == 'r')
                camera.RollSelf(0, 0, 10);
            else if (in[0] == 'y')
                camera.RollSelf(0, 0, -10);
        
            //复位位置
            else if (in[0] == 'R')
            {
                xyz[0] = 60;
                xyz[1] = 0;
                xyz[2] = 0;
                camera.Reset();
            }

            float xyzTF[3] = {xyz[0], xyz[1], xyz[2]};
            camera.Transfer(xyzTF);

            ret = camera.Project(
                xyzTF,
                retXY,
                &retDepth);

            printf("Project(%02X): xyz: %.2f %.2f %.2f retXY: %d %d, dep: %.3f \r\n",
                ret, xyzTF[0], xyzTF[1], xyzTF[2], retXY[0], retXY[1], retDepth);
        }
    }

    return 0;
}

#elif (TEST == 0)

#include "lib_jpeg_adapt.h"
#include "lib_png_adapt.h"
#include "util_bmp.h"
#include "util_delay.h"
#include "plat_display.h"

int32_t main()
{
    PlatDisplay display;
    Image image = display.GetMap();

    Image png;
    png.info.format = IMAGE_FORMAT_BGRA;
    png.mem.addr = LibPngGet("./res/signal.png", &png.info.width, &png.info.height, &png.info.pb, LPT_BGRA);
    printf("png: %dx%d - %d \n", png.info.width, png.info.height, png.info.pb);
    
    Image jpg;
    jpg.info.format = IMAGE_FORMAT_RGB;
    jpg.mem.addr = LibJpegGet("./res/map.jpg", &jpg.info.width, &jpg.info.height, &jpg.info.pb);
    printf("jpg: %dx%d - %d \n", jpg.info.width, jpg.info.height, jpg.info.pb);

    while (1)
    {
        for (uint32_t i = 0; i < image.info.width * image.info.height; i++)
            image.mem.addr32[i] = 0x000000FF;
        display.Refresh();
        UtilDelayUs(1000000);

        for (uint32_t i = 0; i < image.info.width * image.info.height; i++)
            image.mem.addr32[i] = 0x0000FF00;
        display.RefreshRect(image.info.width / 2, 0, image.info.width / 2, image.info.height);
        UtilDelayUs(1000000);

        for (uint32_t i = 0; i < image.info.width * image.info.height; i++)
            image.mem.addr32[i] = 0x00FF0000;
        display.RefreshRect(0, image.info.height / 2, image.info.width, image.info.height / 2);
        UtilDelayUs(1000000);

        ImageCover(image, 0, 0, 24, 24, png);
        display.Refresh();
        UtilDelayUs(1000000);

        ImageCover(image, 24, 24, 100, 100, png);
        display.Refresh();
        UtilDelayUs(1000000);

        ImageCover(image, 200, 200, 200, 100, png);
        display.Refresh();
        UtilDelayUs(1000000);

        ImageCover(image, 500, 200, 100, 200, png);
        display.Refresh();
        UtilDelayUs(1000000);

        ImageCover(image, 0, 0, 800, 600, jpg);
        display.Refresh();
        UtilDelayUs(1000000);
    }

    return 0;
}
#endif
